package com.woniuxy.microfixeddepositserver.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.woniuxy.bean.BillBean;
import com.woniuxy.bean.ResultBean;
import com.woniuxy.bean.bank.BankBean;
import com.woniuxy.bean.regularbean.MemberAccountInnerBean;
import com.woniuxy.bean.regularbean.MemberAccountOutBean;
import com.woniuxy.microfixeddepositserver.bean.FixedTimeDepositBean;
import com.woniuxy.microfixeddepositserver.bean.FundManagerBean;
import com.woniuxy.microfixeddepositserver.bean.ProductDateInfo;
import com.woniuxy.microfixeddepositserver.bean.RiskGradeBean;
import com.woniuxy.microfixeddepositserver.bean.detail.*;
import com.woniuxy.microfixeddepositserver.dao.*;
import com.woniuxy.microfixeddepositserver.feign.MemberFeign;
import com.woniuxy.microfixeddepositserver.feign.WalletFeign;
import com.woniuxy.microfixeddepositserver.service.IRegularService;
import com.woniuxy.microfixeddepositserver.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.joda.time.DateTime;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author: masterhai
 * @date: 2021/4/12:10:07
 * @description: 前端压力太大, 只好在这里拼接一些字段了, 让他们直接渲染
 */
@Service
@Slf4j
public class RegularServiceImpl implements IRegularService {
    @Resource
    private FixedTimeDepositDao fixedTimeDepositDao;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private MemberFeign memberFeign;
    @Resource
    private WorkDayDao workDayDao;
    @Resource
    private WalletFeign walletFeign;
    @Resource
    private RegularDao regularDao;
    @Resource
    private RiskGradeDao riskGradeDao;
    @Resource
    private AgreementDao agreementDao;
    @Resource
    private ProblemDao problemDao;


    @Override
    public ResultBean buyRegular (BillBean billBean) {
        //String userName, Integer fid, double money, Integer choose
        if (ObjectUtils.isEmpty(billBean)) {
            return ResultBean.ParamError();
        }
        Integer code = 0;
        //返回消息
        String msg = "";
        RLock lock = null;
        try {
            //加锁
            lock = redissonClient.getLock(billBean.getMemberName() + "_regular:" + billBean.getProductId());
            //判断锁的状态
            if (! lock.isLocked()) {
                lock.lock(5, TimeUnit.MINUTES);
            }
            //根据产品id查出产品信息
            FixedTimeDepositBean regular = fixedTimeDepositDao.selectByPrimaryKey(billBean.getProductId(), 1);
            if (ObjectUtils.isEmpty(regular)) {
                return ResultBean.ParamError();
            }
            if (regular.getSumCount() <= 0) {
                //当前产品剩余份额判断
                code = 553;
                msg = "剩余产品数量不足,购买失败";
            } else if (billBean.getModifiedPrice() < regular.getMinimumMoney()) {
                code = 554;
                msg = "低于最低起购金额,购买失败";
            } else {
                //1.扣减用户的账户余额
                billBean.setProductType("定期");
                billBean.setOrderType("购买");
                String res = memberFeign.balancePayment(billBean);
                ResultBean resultBean = JSONObject.parseObject(res, ResultBean.class);
                // JSON.parseObject(JSON.parseObject(res).getString("data"), Student.class);
                if (resultBean.getCode() != 200) {
                    //操作不成功直接返回对应失败结果
                    return resultBean;
                }

                // JSON.parseObject(JSON.parseObject(studentInfo).getString("data"), Student.class);
                //2.扣除该定期产品的总份额及增加销售数量及总销售额
                fixedTimeDepositDao.subTotalAndAddSelCount(billBean.getProductId(), billBean.getModifiedPrice());
                //3.获取收益日期
                ProductDateInfo productDateInfo = computeDate(regular, regular.getFid());
                billBean = JSON.parseObject(JSON.parseObject(res).getString("data"), BillBean.class);
                insertAsset(productDateInfo, regular.getFname(), billBean.getMemberName(), billBean.getProductId(), billBean.getModifiedPrice(), 2, regular.getYieldRates(), billBean.getOrderNumber());
                code = 200;
                msg = "购买定期产品成功";
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放锁
            lock.unlock();
        }
        return ResultBean.builder().code(code).msg(msg).build();
    }

    @Override
    public ResultBean getRegularEarnings (String userName) {
        //获取用户购买的所有定期产品的收益信息
        List<MemberAccountInnerBean> regularEarnings = fixedTimeDepositDao.getRegularEarnings(userName);
        if (regularEarnings == null || regularEarnings.size() < 1) {
            return ResultBean.builder().code(556).msg("该用户暂时未购买任何定期产品哦").build();
        }
        //计算所有产品的总收益
        double sumEarning = 0.0;
        //总价值
        double sumOverAllBalance = 0.0;
        //当日总收益
        double todaySumEarning = 0.0;
        for (int i = 0; i < regularEarnings.size(); i++) {
            MemberAccountInnerBean regularEarning = regularEarnings.get(i);
            sumEarning += regularEarning.getTotalEarnings();
            sumOverAllBalance += regularEarning.getOverAllBalance();
            todaySumEarning += regularEarning.getTodayEarnings();
            //格式化小数
            regularEarning.setTotalEarnings((double) Math.round(regularEarning.getTotalEarnings() * 100) / 100);
            regularEarning.setOverAllBalance((double) Math.round(regularEarning.getOverAllBalance() * 100) / 100);
            regularEarning.setTodayEarnings((double) Math.round(regularEarning.getTodayEarnings() * 100) / 100);
        }
        sumOverAllBalance = (double) Math.round(sumOverAllBalance * 100) / 100;
        sumEarning = (double) Math.round(sumEarning * 100) / 100;
        todaySumEarning = (double) Math.round(todaySumEarning * 100) / 100;
        //最终返回
        return ResultBean.builder().code(200).msg("查询用户定期产品收益成功").data(new MemberAccountOutBean(sumOverAllBalance, regularEarnings, sumEarning, todaySumEarning)).build();
    }

    @Override
    public ProductDateInfo computeDate (FixedTimeDepositBean fixedTimeDepositBean, Integer fid) {
        if (ObjectUtils.isEmpty(fixedTimeDepositBean)) {
            fixedTimeDepositBean = fixedTimeDepositDao.selectByPrimaryKey(fid, 1);
        }
        String createDateHour = new DateTime().toString("yyyy-MM-dd:HH");
        String[] split = createDateHour.split(":");
        //获取购买日期
        Integer parchaseDay = Integer.valueOf(split[0].replaceAll("-", ""));
        //获取购买时间
        Integer parchaseHour = Integer.valueOf(split[1]);
        //获取t+n计算收益延期天数
        Integer delayDay = fixedTimeDepositBean.getDelayDay();
        List<Integer> workDates = parchaseHour >= fixedTimeDepositBean.getEndHour() ? workDayDao.getWorkDates(parchaseDay, delayDay + 1) : workDayDao.getWorkDatesIncludeToday(parchaseDay, delayDay + 1);
        //产品计算收益日 ,最大值即收益计算日
        Integer calculateEarningsDay = workDates.get(workDates.size() - 1);

        //计算到期时间
        DateTime dateTime = DateTime.parse(split[0]).plusDays(fixedTimeDepositBean.getPeriod());

        Integer duteDate = Integer.valueOf(dateTime.toString("yyyyMMdd"));
        //到期后资金到账交易日
        Integer accountingDate = fixedTimeDepositBean.getAccountingDate();
        //产品id
        Integer pid = fixedTimeDepositBean.getFid();

        return new ProductDateInfo(pid, parchaseDay, calculateEarningsDay, duteDate, accountingDate);
    }


    @Override
    public void insertAsset (ProductDateInfo productDateInfo, String fName, String username, Integer fid, Double money, Integer choose, Double yieldRates, Long orderNumber) {
        MemberAccountInnerBean innerBean = new MemberAccountInnerBean();
        innerBean.setMemberAccount(username);
        innerBean.setFixedDepositId(fid);
        innerBean.setUnConfirmCapital(money);
        innerBean.setDueToOPlan(choose);
        innerBean.setParchaseDay(productDateInfo.getParchaseDay());
        innerBean.setAccountingDate(productDateInfo.getAccountingDate());
        innerBean.setDuteDate(productDateInfo.getDuteDate());
        innerBean.setCalculateEarningsDay(productDateInfo.getCalculateEarningsDay());
        innerBean.setYieldRates(yieldRates);
        innerBean.setOverAllBalance(money);
        innerBean.setOrderNumber(orderNumber);
        innerBean.setProductName(fName);
        fixedTimeDepositDao.insertAsset(innerBean);
    }

    @Override
    public ResultBean sellRegular (BillBean billBean) {
        //根据资产id查询产品id
        Integer fid = billBean.getProductId();
        //根据产品id查出产品信息
        FixedTimeDepositBean regular = fixedTimeDepositDao.selectByPrimaryKey(fid, 1);
        //获取扣除书续费之后的可提现金额
        Double totalMoney = getWithdrawalMoney(regular, billBean);
        //1.增加用户的账户余额(负数)
        billBean.setModifiedPrice(- totalMoney);
        billBean.setProductType("定期");
        billBean.setOrderType("领取");
        //2.在订单表中增加数据
        String res = memberFeign.balancePayment(billBean);
        ResultBean resultBean = JSONObject.parseObject(res, ResultBean.class);
        if (resultBean.getCode() != 200) {
            //操作不成功直接返回对应失败结果
            return resultBean;
        }
        //删除跟人资产中心对应数据
        int row = fixedTimeDepositDao.removeMemberEarningsInfo(billBean.getPid());
        if (row <= 0) {
            return ResultBean.builder().code(558).msg("赎回定期产品失败").build();
        }
        return ResultBean.builder().code(200).msg("赎回成功,预计" + regular.getAccountingDate() + "个交易日内到账").build();
    }

    //获取不同存款时间扣除交易手续费过后可提现的金额(对应百分比区间响应基准费率折扣,如时间段10%以内手续费九折,20就是8折)
    public Double getWithdrawalMoney (FixedTimeDepositBean regular, BillBean billBean) {
        MemberAccountInnerBean bean = fixedTimeDepositDao.getEarningsById(billBean.getPid());
        //获取当前时间
        Integer todayTime = Integer.valueOf(new DateTime().toString("yyyyMMdd"));
        if (todayTime >= bean.getDuteDate()) {
            //到期不需要手续费
            billBean.setTransactionFee(0.0);
            return 0.0;
        }
        //要求的购买周期
        Integer period = regular.getPeriod();
        //已经购买的天数
        Integer buyDay = bean.getBuyDay();
        //确定当前已经购买的百分比数(整10)
        int rang = buyDay / (period / 10);
        //对应的费率折扣
        int payDiscount = (10 - rang) > 0 ? (10 - rang) : 0;
        //计算手续费
        double payMoney = regular.getProcedureRates() * (bean.getOverAllBalance() - bean.getTotalEarnings()) * payDiscount;
        billBean.setTransactionFee(payMoney);
        //将手续费存入数据库
        regularDao.saveRedemptionFeeIncome("定期", payMoney);
        return bean.getOverAllBalance() - payMoney;

    }


    @Override
    public ResultBean getProductDeatil (RegularQuery regularQuery) {
        //1.获取基础产品信息
        FixedTimeDepositBean d = fixedTimeDepositDao.selectByPrimaryKey(regularQuery.getFid(), 1);
        log.info("1");
        //2.获取收益日对象
        InvestmentCycleBean earningsDay = getEarningsDay(d, null);
        log.info("2");
        //3.获取交易说明
        String[] instructions = getInstructions(d.getPeriod());
        log.info("3");
        //4.获取机构说明
        List<SecurityBean> securityBean = regularDao.getOrganization();
        log.info("4");
        //5.获取产品描述
        String description = getDescription(d);
        log.info("5");
        //6.获取交易规则
        TradingRules tradingRules = getTradingRules(d);
        log.info("6");
        //7.获取信息披露实体类
        AnnounceBean announceBean = getAnnounce(d);
        log.info("7");
        //8.获取常见问题
        List<ProblemBean> problemList = problemDao.getAllProblem();
        log.info("8");
        ProductDetailsBean productDetailsBean = new ProductDetailsBean("定期", d.getFid(), d.getFname(), d.getBjImg(), (double) Math.round(d.getYieldRates() * 10000) / 10000, d.getPeriod(), d.getMinimumMoney(), earningsDay, instructions, securityBean, description, tradingRules, announceBean, problemList, d.getRiskRevel());
        return ResultBean.builder().code(200).msg("查询产品详情成功").data(productDetailsBean).build();
    }

    @Override
    public ResultBean findBuyRegular (String memberName) {
        List<OwnRegularBean> buyRegular = regularDao.getBuyRegular(memberName);
        if (buyRegular == null || buyRegular.size() <= 0) {
            return ResultBean.builder().code(710).msg("该用户无定期购买记录").build();
        }
        Double yesterdayEarnings = 0.0;
        //持有收益
        Double ownEarnings = 0.0;
        //总资产
        Double allMoney = 0.0;
        for (int i = 0; i < buyRegular.size(); i++) {
            OwnRegularBean regularBean = buyRegular.get(i);
            String s = regularBean.getDoDay().toString();
            //2015 03 12
            String year = s.substring(0, 4);
            String month = s.substring(4, 6);
            String day = s.substring(6, 8);
            if (month.startsWith("0")) {
                month = month.substring(1);
            }
            if (day.startsWith("0")) {
                day = day.substring(1);
            }
            String earningsDay = year + "-" + month + "-" + day;
            regularBean.setEarningsDay(earningsDay);
            yesterdayEarnings += regularBean.getTodayEarnings();
            //计算出所有本金,格式化2位小数
            allMoney = allMoney + regularBean.getConfirmCapital() + regularBean.getUnConfirmCapital();
            ownEarnings += regularBean.getTotalEarnings();
            regularBean.setTodayEarnings((double) Math.round(regularBean.getTodayEarnings() * 100) / 100);
            regularBean.setTotalEarnings((double) Math.round(regularBean.getTotalEarnings() * 100) / 100);
        }
        OutterRegularBean outterRegularBean = new OutterRegularBean();
        outterRegularBean.setOwnRegularBeans(buyRegular);
        outterRegularBean.setYesterdayEarnings((double) Math.round(yesterdayEarnings * 100) / 100);
        outterRegularBean.setOwnEarnings((double) Math.round(ownEarnings * 100) / 100);
        //查询总收益
        List<OwnRegularBean> beans = regularDao.getAllEarnings();
        Double sumEarnings = 0.0;
        for (OwnRegularBean bean : beans) {
            sumEarnings += bean.getTotalEarnings();
        }
        outterRegularBean.setSumEarnings((double) Math.round(sumEarnings * 100) / 100);
        //所有本金+持有收益=总资产
        outterRegularBean.setAllMoney((double) Math.round((allMoney + ownEarnings) * 100) / 100);
        return ResultBean.builder().code(200).msg("查询用户购买的定期产品成功").data(outterRegularBean).build();
    }

    @Override
    public ResultBean getMoney (Integer pid, Integer fid) {

        //计算当前赎回的费用
        MemberAccountInnerBean bean = fixedTimeDepositDao.getEarningsById(pid);
        //获取当前时间
        Integer todayTime = Integer.valueOf(new DateTime().toString("yyyyMMdd"));
        if (todayTime >= bean.getDuteDate()) {
            //到期不需要手续费
            return ResultBean.builder().code(199).msg("您已存够足够,当前提现无需手续费").build();
        }
        //根据产品Id查询产品投资周期
        FixedTimeDepositBean regular = fixedTimeDepositDao.selectByPrimaryKey(fid, 1);
        //已经购买的天数
        Integer buyDay = bean.getBuyDay();
        //确定当前已经购买的百分比数(整10)
        int rang = buyDay / (regular.getPeriod() / 10);
        //对应的费率折扣
        int payDiscount = (10 - rang) > 0 ? (10 - rang) : 0;
        //计算手续费
        double payMoney = regular.getProcedureRates() * (bean.getOverAllBalance() - bean.getTotalEarnings()) * payDiscount;
        String money = String.format("%.2f", payMoney);
        return ResultBean.builder().code(200).msg("您已经持有当前产品" + buyDay + "天,现在卖出需要收取" + money + "元手续费," +
                "再继续持有" + (regular.getPeriod() - buyDay) + "天可以免费提取.").build();
    }

    private AnnounceBean getAnnounce (FixedTimeDepositBean depositBean) {
        String productType = depositBean.getProductType();
        String productName = depositBean.getFname();
        String format = new DateTime(depositBean.getCreateTime()).toString("yyyy-MM-dd HH:mm:ss");
        //String format = new SimpleDateFormat("").format(depositBean.getCreateTime());
        String[] strings = format.split(" ")[0].split("-");
        String setUpDate = strings[0] + "年" + strings[1] + "月" + strings[2] + "日";
        String administrator = depositBean.getCustodian();
        String custodian = depositBean.getTrustee();
        String scope = depositBean.getInvestmentScope();
        FundManagerBean managerBean = depositBean.getFundManager();
        String manager = new StringBuffer().append(managerBean.getMname()).append(managerBean.getCalls()).append(",").append(managerBean.getGraduateSchool())
                .append(managerBean.getDepartment()).append(managerBean.getEducationLevel()).append(".").append(managerBean.getBackground()).toString();
        List<AgreementBean> agreementBeans = agreementDao.getAllAgreement();
        return new AnnounceBean(productType, productName, setUpDate, administrator, custodian, scope, manager, agreementBeans);
    }

    private TradingRules getTradingRules (FixedTimeDepositBean depositBean) {
        Integer minMoney = depositBean.getMinimumMoney();
        String drawMoney = minMoney + "元起,购买金额为1元的整数倍";
        String toillustrate = "资金将在领取后的" + depositBean.getAccountingDate() + "个交易日内回到原购买账户,";
        String openDay = "可在开放日10点-15点领取,也可在开放日之前预约领取,若未领取则默认缓存至下一周.如开放日遇到非交易日," +
                "可能顺延或提前开放,收益按实际计息天数计算";
        String rule = "购买的下一个交易日开始计算收益,节假日照常计算;收益每日累计,按周期发放(" + DateUtil.conversionDay(depositBean.getPeriod()) + "),现金收益将在" + depositBean.getAccountingDate()
                + "个交易日内直接发放至原购买账户";
        String cost = "购买无手续费,根据存款时间达成度收取对应的领取手续费(达成度越高手续费越低),到期领取无需手续费";
        List<BankBean> bankList = regularDao.getBankList();
        //更改银行对象限额的单位
        for (int i = 0; i < bankList.size(); i++) {
            BankBean bank = bankList.get(i);
            Integer dayLimit = Integer.valueOf(bank.getDayLimit());
            Integer sinLimit = Integer.valueOf(bank.getSingleLimit());
            //修改限额单位
            if (dayLimit >= 10000 && dayLimit % 10000 == 0) {
                bank.setDayLimit(dayLimit / 10000 + "万");
            } else if (dayLimit >= 1000 && dayLimit % 1000 == 0) {
                bank.setDayLimit(dayLimit / 1000 + "千");
            }
            if (sinLimit >= 10000 && sinLimit % 10000 == 0) {
                bank.setSingleLimit(sinLimit / 10000 + "万");
            } else if (sinLimit >= 1000 && sinLimit % 1000 == 0) {
                bank.setSingleLimit(sinLimit / 1000 + "千");
            }
        }
        return new TradingRules(minMoney, drawMoney, toillustrate, openDay, rule, cost, bankList);
    }

    private String getDescription (FixedTimeDepositBean depositBean) {
        RiskGradeBean infoById = riskGradeDao.getInfoById(depositBean.getRiskRevel());
        return "该产品属于" + depositBean.getTypeName() + "产品," + infoById.getGDescription();
    }


    private String[] getInstructions (Integer period) {
        String begin = "每" + DateUtil.conversionDay(period) + "为一期";
        String context1 = "可在到期开放日追加或领取,若未领取则默认持续存至下一期";
        String context2 = "*当期实际期限以投资周期展示为准,收益按当期实际计息天数计算";
        String[] strings = new String[2];
        strings[0] = begin + context1;
        strings[1] = context2;
        return strings;

    }


    private InvestmentCycleBean getEarningsDay (FixedTimeDepositBean depositBean, Integer fid) {
        ProductDateInfo dateInfo = computeDate(depositBean, fid);
        //产品购买日
        String parchaseDay = String.valueOf(dateInfo.getParchaseDay());
        String buyDay = parchaseDay.substring(0, 4) + "/" + parchaseDay.substring(4, 6) + "/" + parchaseDay.substring(6);
        //产品计算收益日,如2021 04 03
        String calculate = String.valueOf(dateInfo.getCalculateEarningsDay());
        String calculateEarningsDay = calculate.substring(0, 4) + "/" + calculate.substring(4, 6) + "/" + calculate.substring(6);
        //产品到期日
        String dute = String.valueOf(dateInfo.getDuteDate());
        String duteDate = dute.substring(0, 4) + "/" + dute.substring(4, 6) + "/" + dute.substring(6);
        //到期后资金到账日期
        String accountingDate = dateInfo.getAccountingDate() + "个交易日内";
        return new InvestmentCycleBean(buyDay, calculateEarningsDay, duteDate, accountingDate);

    }
}
